package org.eden.rpc.core.client.pooled;

import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;
import org.eden.rpc.common.exception.ConnectException;
import org.eden.rpc.core.client.NettyClientProxy;
import org.eden.rpc.core.client.RpcClient;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DefaultRpcClientPool {

    private final SimpleBlockingNettyConnectionPool connectionPool;

    private final Map<Integer, NettyClientProxy> proxyCache = new ConcurrentHashMap<>();

    private final ThreadLocal<RpcClient> clientHolder = new ThreadLocal<>();

    private static final int DEFAULT_CAPACITY = 1 << 8;
    private static final int WAITING_TIME_SECONDS = 5;

    public DefaultRpcClientPool(String host, int port) {
        this(host, port, DEFAULT_CAPACITY);
    }

    public DefaultRpcClientPool(String host, int port, int capacity) {
        connectionPool = new SimpleBlockingNettyConnectionPool(host, port, capacity);
    }

    public <T> T getService(Class<T> clazz) throws ConnectException {
        Future<RpcClient> future = connectionPool.getConnection();
        RpcClient client;
        try {
            client = future.get(WAITING_TIME_SECONDS, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ConnectException("服务器繁忙");
        }
        NettyClientProxy proxy;
        if (proxyCache.containsKey(client.hashCode())) {
            proxy = proxyCache.get(client.hashCode());
        } else {
            proxy = new NettyClientProxy(client);
            proxyCache.put(client.hashCode(), proxy);
        }
        clientHolder.set(client);
        return proxy.getService(clazz);
    }

    public void retrieve() {
        RpcClient client = clientHolder.get();
        connectionPool.retrieve(client);
        clientHolder.remove();
    }

}
